#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "PictPort.h"

#include "Class.h"
#include "String.h"
#include "Picture.h"
#include "ObjArray.h"

NewMetaImpl0(PictPort, PrintPort);

//---- PictPort ----------------------------------------------------------------

PictPort::PictPort(Picture *p) : PrintPort()
{
	hascolor= TRUE;
	pict= p;
	DevOpenPage(0);
}

PictPort::~PictPort()
{
	FlushMyText();
	PutCode(cPicEnd);
	if (pict)
		pict->Set(pagebbox, (byte*)pagebuf->Base(), (int)pagebuf->tell(), map);
	SafeDelete(pagebuf);
}

void PictPort::DevOpenPage(int)
{
	pagebuf= new MemBuf;
	map= new ObjArray;

	lastfont= 0;
	lastextent= lastpos= gPoint0;
	lastdia= gPoint0;
	lastpsz= 1;
	laststartangle= lastendangle= 0;
	lastcap= eDefaultCap;
	for (int i= 0; i < map->Size(); i++)
		map->AtPut(i, 0);
	//pagebuf->seek(0);
}

void PictPort::DevClosePage()
{
	FlushMyText();
	PutCode(cPicEnd);
	if (pict)
		pict->Set(pagebbox, (byte*)pagebuf->Base(), (int)pagebuf->tell(), map);
}

void PictPort::PutInt(int i)
{
	/*
	PutByte(i >> 24);
	PutByte(i >> 16);
	PutByte(i >> 8);
	PutByte(i);
	*/
	pagebuf->sputn((char*) &i, 4);
}

void PictPort::PutShort(short s)
{
	/*
	PutByte(i >> 8);
	PutByte(i);
	*/
	pagebuf->sputn((char*) &s, 2);
}

void PictPort::PutPoint(byte code, const Point &p)
{
	if (p.x != 0) {
		if (p.x >= -128 && p.x < 128) {
			code+= 0x04;
		} else if (p.x >= -32768 && p.x < 32768) {
			code+= 0x08;
		} else {
			code+= 0x0c;
		}
	}
	if (p.y != 0) {
		if (p.y >= -128 && p.y < 128) {
			code+= 0x01;
		} else if (p.y >= -32768 && p.y < 32768) {
			code+= 0x02;
		} else {
			code+= 0x03;
		}
	}
	PutCode(code);
	if (p.x != 0) {
		if (p.x >= -128 && p.x < 128) {
			PutByte(p.x);
		} else if (p.x >= -32768 && p.x < 32768) {
			PutShort(p.x);
		} else {
			PutInt(p.x);
		}
	}
	if (p.y != 0) {
		if (p.y >= -128 && p.y < 128) {
			PutByte(p.y);
		} else if (p.y >= -32768 && p.y < 32768) {
			PutShort(p.y);
		} else {
			PutInt(p.y);
		}
	}
}

void PictPort::PutPos(const Point &pos)
{
	Point delta(pos-lastpos);
	lastpos= pos;

	if (delta.x >= -32 && delta.x < 32 && delta.y == 0)
		PutCode(cPicXMove0+delta.x+32);
	else
		PutPoint(cPicMove, delta);
}

void PictPort::PutRect(const Rectangle &r)
{
	PutPos(r.origin);

	Point delta(r.extent - lastextent);

	if (delta.x != 0 || delta.y != 0) {
		lastextent= r.extent;
		PutPoint(cPicExtent, delta);
	}
}

void PictPort::PutObject(int code, Object *op)
{
	PutCode(code);
	PutShort(map->Index(op));
}

void PictPort::PutInk()
{
	if (lastink != lastink2)
		PutObject(cPicInk, lastink2= lastink);
}

void PictPort::PutSize(int s)
{
	if (s >= 0 && lastpsz != s) {
		PutCode(cPicPensize);
		PutByte(s);
		lastpsz= s;
	}
}

void PictPort::PutCap(GrLineCap cap)
{
	if (cap != lastcap) {
		PutCode(cPicPenCap);
		PutByte(cap);
		lastcap= cap;
	}
}

void PictPort::PutAngle(int s, int e)
{
	if (s != laststartangle) {
		PutCode(cPicStartAngle);
		PutShort(s);
		laststartangle= s;
	}
	if (e != lastendangle) {
		PutCode(cPicEndAngle);
		PutShort(e);
		lastendangle= e;
	}
}

void PictPort::PutDia(const Point &e)
{
	if (e != lastdia) {
		PutPoint(cPicCornerDia, e);
		lastdia= e;
	}
}

void PictPort::DevClip(const Rectangle &clr)
{
	PutRect(clr);
	PutCode(cPicClip);
}

void PictPort::DevStrokeLine(int psz, const Rectangle &r, GrLineCap cap,
					     const Point &p1, const Point &p2)
{
	Merge(r);
	PutInk();
	Point p(p2-p1);
	PutSize(psz);
	PutCap(cap);
	PutPos(p1);
	PutPoint(cPicLine, p);
	lastpos+= p;
}

extern Ink *gTbInk;

void PictPort::DevShowChar(Font *fp, const Point&, Rune c, const Rectangle &r)
{
	Merge(r);

	lastink= gTbInk;
	PutInk();
	PutPos(r.origin+Point(0, fp->Ascender()));
	if (lastfont != fp)
		PutObject(cPicFont, lastfont= fp);
	if (c < 32 || c >= 128)   // need escape
		PutCode(cPicEsc);
	PutChar(c);
	lastpos.x+= fp->Width(c);
}

void PictPort::DevStrokeRect(int psz, const Rectangle &r)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutSize(psz);
	PutCode(cPicStrokeRect);
}

void PictPort::DevFillRect(const Rectangle &r)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutCode(cPicFillRect);
}

void PictPort::DevStrokeOval(int psz, const Rectangle &r)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutSize(psz);
	PutCode(cPicStrokeOval);
}

void PictPort::DevFillOval(const Rectangle &r)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutCode(cPicFillOval);
}

void PictPort::DevStrokeRRect(int psz, const Rectangle &r, const Point &dia)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutSize(psz);
	PutDia(dia);
	PutCode(cPicStrokeRRect);
}

void PictPort::DevFillRRect(const Rectangle &r, const Point &dia)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutDia(dia);
	PutCode(cPicFillRRect);
}

void PictPort::DevStrokeWedge(int psz, GrLineCap cap, const Rectangle &r,
		int s, int d)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutSize(psz);
	PutCap(cap);
	PutAngle(s, d);
	PutCode(cPicStrokeWedge);
}

void PictPort::DevFillWedge(const Rectangle &r, int s, int d)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutAngle(s, d);
	PutCode(cPicFillWedge);
}

void PictPort::DevStrokePolygon(const Rectangle &r, Point *pts, int n,
					GrPolyType t, int psz, GrLineCap cap)
{
	Merge(r);
	PutPos(r.origin);
	PutInk();
	PutSize(psz);
	PutCap(cap);
	PutCode(cPicStrokePoly);
	PutByte(t);
	PutShort(n);
	for (int i= 0; i < n; i++)
		PutPoint(0, pts[i]);
}

void PictPort::DevFillPolygon(const Rectangle &r, Point *pts, int n, GrPolyType t)
{
	Merge(r);
	PutPos(r.origin);
	PutInk();
	PutCode(cPicFillPoly);
	PutByte(t);
	PutShort(n);
	for (int i= 0; i < n; i++)
		PutPoint(0, pts[i]);
}

void PictPort::DevShowBitmap(const Rectangle &r, struct Bitmap *bmp)
{
	Merge(r);
	PutInk();
	PutRect(r);
	PutObject(cPicShowBitmap, bmp);
}

void PictPort::DevShowPicture(const Rectangle &r, Picture *pict)
{
	Merge(r);
	PutRect(r);
	PutObject(cPicShowPicture, pict);
}

void PictPort::DevGiveHint(int code, int len, void *vp)
{
	PutCode(cPicHint);
	PutInt(code);
	if (vp) {
		PutInt(len);
		pagebuf->sputn((char*) vp, len);
	} else
		PutInt(0);
}

